package day01;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Jetwang
 * @version 1.0
 * @since 2023/3/19 13:53
 */
public class BlockingQueue02<E> implements BlockingQueue<E>{
    private final E[] array;
    private int head;
    private int tail;
    // private int size;
    private AtomicInteger size = new AtomicInteger(0);

    @SuppressWarnings("all")
    public BlockingQueue02(int capacity) {
        array = (E[]) new Object[capacity];
    }

    private ReentrantLock tailLock = new ReentrantLock();
    private Condition tailWaits = tailLock.newCondition();

    private ReentrantLock headLock = new ReentrantLock();
    private Condition headWaits = tailLock.newCondition();


    private boolean isEmpty() {
        return size.get() == 0;
    }

    private boolean isFull() {
        return size.get() == array.length;
    }

    @Override
    public void offer(E e) throws InterruptedException {
        tailLock.lockInterruptibly();
        int c; // 添加前元素个数
        try {
            // 1. 队列满,进行等待
            while (isFull()) {
                tailWaits.await();
            }
            array[tail] = e;
            if (++tail == array.length) {
                tail = 0;
            }
            // size++;
            c = size.getAndIncrement();
            // headWaits.signal(); 会报错 要配对
            if (c + 1 < array.length) {
                tailWaits.signal();
            }
        } finally {
            tailLock.unlock();
        }

        // 写成平级代码，避免死锁    0 -> 1    1 -> 2   2 -> 3
        if (c == 0) {
            headLock.lock();    // offer01, offer02, offer03...
            try {
                headWaits.signal();
            } finally {
                headLock.unlock();
            }
        }

    }

    @Override
    public boolean offer(E e, long timeout) throws InterruptedException {
        return false;
    }

    @Override
    public E poll() throws InterruptedException {
        E e;
        headLock.lockInterruptibly();
        int c; // 取走前元素个数
        try {
            // 1. 队列空，等待
            while (isEmpty()) {
                headWaits.await();
            }
            e = array[head];
            array[head] = null; // help GC
            if (++head == array.length) {
                head = 0;
            }
            // size--;
            c = size.getAndDecrement();
            if (c > 1) {
                headWaits.signal();
            }
        } finally {
            headLock.unlock();
        }


        if (c == array.length) {
            // 写成平级代码，避免死锁
            tailLock.lock();
            try {
                tailWaits.signal();
            } finally {
                tailLock.unlock();
            }
        }
        return e;
    }
}
